package ua.khpi.si.kit49.diploma.controllers;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import java.util.Map;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.gson.Gson;

import ua.khpi.si.kit49.diploma.core.Constants;
import ua.khpi.si.kit49.diploma.core.RepliedRoute;
import ua.khpi.si.kit49.diploma.core.Route;
import ua.khpi.si.kit49.diploma.db.dto.City;
import ua.khpi.si.kit49.diploma.service.CityHolder;
import ua.khpi.si.kit49.diploma.service.CityService;
import ua.khpi.si.kit49.diploma.service.RouteService;

/**
 * Controller is in charge of operations with searching routes
 * 
 * @author netstalk3r
 * 
 */

@Controller
public class RoutesController {

	/**
	 * Logger
	 */
	private static final Logger log = Logger.getLogger(RoutesController.class);

	/**
	 * service related to operation with cities
	 */
	@Autowired(required = true)
	private CityService cityService;

	/**
	 * message recourse
	 */
	@Autowired(required = true)
	private ReloadableResourceBundleMessageSource messageSource;

	/**
	 * service to find best routes
	 */
	@Autowired(required = true)
	private RouteService routeService;

	// ////////////////////////////////////////////////////////////////
	// mapping for methods
	// ////////////////////////////////////////////////////////////////
	private static final String ROUTE_PAGE_MAPPING = "/routes";
	private static final String BEST_ROUTES_MAPPING = "/bestroutes";
	// ////////////////////////////////////////////////////////////////

	private static final Integer LOWER_LIMIT_CITIES_ID = 0;

	/**
	 * method for getting routes page
	 * 
	 * @param model
	 *            model map
	 * @param loc
	 *            current localization
	 * @return route page or error
	 */
	@RequestMapping(value = ROUTE_PAGE_MAPPING, method = RequestMethod.GET)
	public String getRoutePage(ModelMap model, Locale loc) {
		try {
			log.info("Get routes page");
			log.debug("Language - " + loc.getLanguage());
			List<City> listWithCities = cityService.getAllCities();
			Map<Integer, String> cities = new LinkedHashMap<Integer, String>();
			for (int i = 0; i < listWithCities.size(); i++) {
				String cityName = messageSource.getMessage("company.city."
						+ listWithCities.get(i).getName(), null,
						Constants.DEFAULT_MESSAGE, loc);
				cityName = StringEscapeUtils.unescapeJava(cityName);
				cities.put(listWithCities.get(i).getId(), cityName);
			}
			model.put("citiesList", cities);
			return Constants.ROUTES_PAGE;
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			String errorMessage = messageSource.getMessage(e.getMessage(),
					null, e.getMessage(), loc);
			errorMessage = StringEscapeUtils.unescapeJava(errorMessage);
			model.put("errorMessage", errorMessage);
			return Constants.ERROR_PAGE;
		}
	}

	/**
	 * method for getting the best routes
	 * 
	 * @param strat
	 *            id of started city
	 * @param finish
	 *            id of finished city
	 * @param loc
	 *            current localization
	 * @return reply with routes or with error
	 */
	@RequestMapping(value = BEST_ROUTES_MAPPING, method = RequestMethod.POST)
	@ResponseBody
	public String getBestRoutes(@RequestParam("start") String strat,
			@RequestParam("finish") String finish, Locale loc) {
		log.info("id start - " + strat);
		log.info("id finish - " + finish);
		Integer cityStartId;
		Integer cityFinishId;
		try {
			cityStartId = Integer.parseInt(strat);
			cityFinishId = Integer.parseInt(finish);
		} catch (NumberFormatException e) {
			log.error(e.getMessage());
			String error = messageSource.getMessage(
					"company.error.city.illegal.id.format", null,
					Constants.DEFAULT_MESSAGE, loc);
			error = StringEscapeUtils.unescapeJava(error);
			return error;
		}
		Integer upperLimit = CityHolder.getInstance().getAmountOfCity();
		Boolean validStart = cityStartId > LOWER_LIMIT_CITIES_ID
				& cityStartId <= upperLimit;
		Boolean validFinish = cityFinishId > LOWER_LIMIT_CITIES_ID
				& cityFinishId <= upperLimit;

		Set<Route> bestRoutes = null;
		if (validStart && validFinish) {
			bestRoutes = routeService.getBestRoutes(cityStartId, cityFinishId);
		} else {
			String error = messageSource.getMessage(
					"company.error.city.illegal.id.format", null,
					Constants.DEFAULT_MESSAGE, loc);
			error = StringEscapeUtils.unescapeJava(error);
			log.equals(error);
			return error;
		}
		List<RepliedRoute> listRepliesRoutes = routeService
				.convertToRepliedRoutes(bestRoutes);
		for (int i = 0; i < listRepliesRoutes.size(); i++) {
			RepliedRoute repliedRoute = listRepliesRoutes.get(i);
			List<String> cities = repliedRoute.getCitiesNames();
			for (int j = 0; j < cities.size(); j++) {
				String cityName = messageSource.getMessage("company.city."
						+ cities.get(j), null, Constants.DEFAULT_MESSAGE, loc);
				cityName = StringEscapeUtils.unescapeJava(cityName);
				cities.set(j, cityName);
			}
			String roadQuality = messageSource.getMessage(
					"company.route.road.quality."
							+ repliedRoute.getRoadQuality(), null,
					Constants.DEFAULT_MESSAGE, loc);
			roadQuality = StringEscapeUtils.unescapeJava(roadQuality);
			repliedRoute.setRoadQuality(roadQuality);
			String roadPriority = messageSource.getMessage(
					"company.route.road.priority."
							+ repliedRoute.getRoadPriority(), null,
					Constants.DEFAULT_MESSAGE, loc);
			roadPriority = StringEscapeUtils.unescapeJava(roadPriority);
			repliedRoute.setRoadPriority(roadPriority);
		}

		Gson gson = new Gson();
		String result = gson.toJson(listRepliesRoutes);

		log.info(result);

		return result;
	}
}
